#ifndef _W25QXX_H
#define _W25QXX_H

#ifdef __cplusplus
extern "C"{
#endif

#include <stdbool.h>
#include "spi.h"

#define _W25QXX_SPI hspi1
#define _W25QXX_CS_GPIO W25Qxx_CS_GPIO_Port
#define _W25QXX_CS_PIN W25Qxx_CS_Pin
#define _W25QXX_USE_FREERTOS 0
#define _W25QXX_DEBUG 0
#define _W25QXX_CS_(_x) HAL_GPIO_WritePin(_W25QXX_CS_GPIO, _W25QXX_CS_PIN, ((_x) ? GPIO_PIN_SET : GPIO_PIN_RESET))

//W25qxx寄存器
#define W25QXX_DUMMY_BYTE 0xA5       //伪字节
#define JEDEC_ID 0x9F                //主体ID
#define UNIQUE_ID 0x4B               //唯一ID
#define WRITE_ENABLE 0x06            //写使能
#define WRITE_DISABLE 0x04           //写失能
#define READ_STATUS_REGISTER_1 0x05  //读状态寄存器1
#define READ_STATUS_REGISTER_2 0x35  //读状态寄存器2
#define READ_STATUS_REGISTER_3 0x15  //读状态寄存器3
#define WRITE_STATUS_REGISTER_1 0x01 //写状态寄存器1
#define WRITE_STATUS_REGISTER_2 0x31 //写状态寄存器2
#define WRITE_STATUS_REGISTER_3 0x11 //写状态寄存器3
#define CHIP_ERASE 0xC7              //擦除芯片
#define SECTOR_ERASE 0x20            //擦除扇区
#define BLOCK_ERASE 0xD8             //擦除块
#define FAST_READ 0x0B               //快速读取
#define PAGE_PROGRAM 0x02            //页编程

  //适用的W25qxx型号
  typedef enum
  {
    W25Q10 = 1,
    W25Q20,
    W25Q40,
    W25Q80,
    W25Q16,
    W25Q32,
    W25Q64,
    W25Q128,
    W25Q256,
    W25Q512,

  } W25QXX_ID_t;

  //W25qxx相关参数
  typedef struct
  {
    W25QXX_ID_t ID;
    uint8_t UniqID[8];
    uint16_t PageSize;
    uint32_t PageCount;
    uint32_t SectorSize;
    uint32_t SectorCount;
    uint32_t BlockSize;
    uint32_t BlockCount;
    uint32_t CapacityInKiloByte;
    uint8_t StatusRegister1;
    uint8_t StatusRegister2;
    uint8_t StatusRegister3;
    uint8_t Lock;

  } w25qxx_t;
  extern w25qxx_t w25qxx;

  // in Page,Sector and block read/write functions, can put 0 to read maximum bytes
  bool W25qxx_Init(void);

  void W25qxx_EraseChip(void);
  void W25qxx_EraseSector(uint32_t SectorAddr);
  void W25qxx_EraseBlock(uint32_t BlockAddr);

  uint32_t W25qxx_PageToSector(uint32_t PageAddress);
  uint32_t W25qxx_PageToBlock(uint32_t PageAddress);
  uint32_t W25qxx_SectorToBlock(uint32_t SectorAddress);
  uint32_t W25qxx_SectorToPage(uint32_t SectorAddress);
  uint32_t W25qxx_BlockToPage(uint32_t BlockAddress);

  bool W25qxx_IsEmptyPage(uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_PageSize);
  bool W25qxx_IsEmptySector(uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_SectorSize);
  bool W25qxx_IsEmptyBlock(uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_BlockSize);

  void W25qxx_WriteByte(uint8_t pBuffer, uint32_t Bytes_Address);
  void W25qxx_WritePage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_PageSize);
  void W25qxx_WriteSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_SectorSize);
  void W25qxx_WriteBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_BlockSize);

  void W25qxx_ReadByte(uint8_t *pBuffer, uint32_t Bytes_Address);
  void W25qxx_ReadBytes(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead);
  void W25qxx_ReadPage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_PageSize);
  void W25qxx_ReadSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_SectorSize);
  void W25qxx_ReadBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_BlockSize);

#ifdef __cplusplus
}
#endif

#endif //_W25QXX_H
